/* * Copyright 2011-2014 Eric F. Savage, code@efsavage.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.ajah.email.data; import java.util.Properties; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import lombok.extern.java.Log; import org.springframework.transaction.annotation.Transactional; import com.ajah.email.EmailMessage; import com.ajah.email.EmailRecipient; import com.ajah.util.AjahUtils; import com.ajah.util.StringUtils; import com.ajah.util.config.Config; import com.ajah.util.data.format.EmailAddress; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.simpleemail.AWSJavaMailTransport; import com.amazonaws.services.simpleemail.AmazonSimpleEmailService; import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient; import com.amazonaws.services.simpleemail.model.ListVerifiedEmailAddressesResult; import com.amazonaws.services.simpleemail.model.VerifyEmailAddressRequest; /** * Manages the persistance and transport of email messages. * * @author <a href="http://efsavage.com">Eric F. Savage</a>, <a * href="mailto:code@efsavage.com">code@efsavage.com</a>. * */ @Log public class AmazonSESTransport implements EmailTransport { private static boolean isVerified(final EmailAddress emailAddress, final AmazonSimpleEmailService email, final ListVerifiedEmailAddressesResult verifiedEmails) { if (!verifiedEmails.getVerifiedEmailAddresses().contains(emailAddress.toString())) { email.verifyEmailAddress(new VerifyEmailAddressRequest().withEmailAddress(emailAddress.toString())); return false; } return true; } /** * Sends a message through Amazon's SES service. * * @param message * The message to send. Subject, from and to are required. * @throws AddressException * If there is a problem with one of the email addresses. * @throws MessagingException * If there is a problem with the transport of the message. */ @Override public void send(final EmailMessage message) throws AddressException, MessagingException { AjahUtils.requireParam(message, "message"); AjahUtils.requireParam(message.getSubject(), "message.subject"); AjahUtils.requireParam(message.getFrom(), "message.from"); AjahUtils.requireParam(message.getRecipients(), "message.recipients"); final AWSCredentials credentials = new BasicAWSCredentials(Config.i.get("aws.accessKey", null), Config.i.get("aws.secretKey", null)); if (Config.i.getBoolean("aws.ses.verify", false)) { // Verification is active so we'll need to check that first final AmazonSimpleEmailService email = new AmazonSimpleEmailServiceClient(credentials); final ListVerifiedEmailAddressesResult verifiedEmails = email.listVerifiedEmailAddresses(); boolean verified = true; if (!isVerified(message.getFrom(), email, verifiedEmails)) { log.warning("Sender " + message.getFrom() + " is not verified"); verified = false; } for (final EmailRecipient emailRecipient : message.getRecipients()) { if (!isVerified(emailRecipient.getAddress(), email, verifiedEmails)) { log.warning("Recipient " + emailRecipient.getAddress() + " is not verified"); verified = false; } } if (!verified) { throw new MessagingException("Message not sent because one or more addresses need to be verified"); } } final Properties props = new Properties(); props.setProperty("mail.transport.protocol", "aws"); props.setProperty("mail.aws.user", credentials.getAWSAccessKeyId()); props.setProperty("mail.aws.password", credentials.getAWSSecretKey()); final Session session = Session.getInstance(props); final MimeMessage mimeMessage = new MimeMessage(session); mimeMessage.setFrom(new InternetAddress(message.getFrom().toString())); for (final EmailRecipient emailRecipient : message.getRecipients()) { switch (emailRecipient.getType()) { case BCC: mimeMessage.addRecipient(Message.RecipientType.BCC, new InternetAddress(emailRecipient.toString())); break; case CC: mimeMessage.addRecipient(Message.RecipientType.CC, new InternetAddress(emailRecipient.toString())); break; case TO: mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(emailRecipient.toString())); break; default: mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(emailRecipient.toString())); break; } } mimeMessage.setSubject(message.getSubject()); final String htmlContent = message.getHtml(); if (StringUtils.isBlank(htmlContent)) { // No HTML so we'll just send a plaintext message. mimeMessage.setText(message.getText()); } else { final Multipart multiPart = new MimeMultipart("alternative"); final BodyPart text = new MimeBodyPart(); text.setText(message.getText()); multiPart.addBodyPart(text); final BodyPart html = new MimeBodyPart(); html.setContent(message.getHtml(), "text/html"); multiPart.addBodyPart(html); mimeMessage.setContent(multiPart); } mimeMessage.saveChanges(); final Transport transport = new AWSJavaMailTransport(session, null); transport.connect(); transport.sendMessage(mimeMessage, null); transport.close(); } }